package com.finance.system.controller;

import com.alibaba.dubbo.common.utils.StringUtils;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.finance.base.constant.BaseConstants;
import com.finance.base.enums.OpearteEnum;
import com.finance.base.enums.StateEnum;
import com.finance.base.enums.TargetEnum;
import com.finance.base.exception.BaseException;
import com.finance.framework.controller.BaseController;
import com.finance.framework.controller.Result;
import com.finance.framework.file.FileUtils;
import com.finance.framework.lang.BeanUtils;
import com.finance.framework.lang.Page;
import com.finance.framework.lang.PageResultBO;
import com.finance.rule.service.ISettingLogService;
import com.finance.system.bean.pojo.*;
import com.finance.system.export.UserImportTemplateBean;
import com.finance.system.export.UserParse;
import com.finance.system.imports.ImportCallable;
import com.finance.system.request.UserListReq;
import com.finance.system.request.UserReq;
import com.finance.system.service.IOrganizationService;
import com.finance.system.service.IRoleService;
import com.finance.system.service.IUserService;
import com.finance.util.DateUtil;
import com.finance.util.Excel.ExcelUtil;
import com.finance.util.ParamUtils;
import com.finance.util.encrypt.EncryptUtil;
import com.finance.util.export.ExportBuilder;
import com.finance.util.export.ExportFactory;
import org.apache.commons.collections.CollectionUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.session.InvalidSessionException;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;

/**
 * Created by CBWL on 2017/3/15.
 */
@Controller
@RequestMapping("/system/user")
public class UserController extends BaseController{
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Resource
    private IUserService userService;

    @Resource
    private IRoleService roleService;

    @Resource
    private IOrganizationService organizationService;

    @Resource
    private ISettingLogService settingLogService;

    private ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 登录校验
     * @param userReq
     * @return
     * @throws BaseException
     */
    @RequestMapping("/login")
    public Result login(@Valid UserReq userReq) throws BaseException, IOException {
        UsernamePasswordToken token = new UsernamePasswordToken(userReq.getCode(),userReq.getPasswd());
        Subject subject = SecurityUtils.getSubject();
        subject.login(token);
        try {
            if(subject.isAuthenticated()){
                User user = (User)subject.getSession().getAttribute("authUser");
                Menu menu = userService.getMenuTree(user);
                subject.getSession().setAttribute("menu", JSON.toJSONString(menu));
                return this.getSuccessResult("登录成功");
            }
        } catch (InvalidSessionException e) {
            e.printStackTrace();
        }
        return this.getSuccessResult("登录失败");
    }

    /**
     * 获取当前用户所有菜单
     * @return
     * @throws BaseException
     * @throws IOException
     */
    @RequestMapping("/getMenus")
    public Result getMenu() throws BaseException, IOException {
        User user = this.getAuthUser();
        if(user==null){
           throw new BaseException(BaseConstants.ERR_UNKONW_USER);
        }
        Menu menu = userService.getMenuTree(user);
        return this.getSuccessResult(menu);
    }

    /**
     * 登陆页
     * @return
     */
    @RequestMapping("/login.htm")
    public String login(){
        return "system/user/login";
    }

    /**
     * 退出
     */
    @RequestMapping("/logout.htm")
    public void loginout(){
        Subject currentUser = SecurityUtils.getSubject();
        currentUser.logout();
    }

    @RequestMapping("/authThird")
    public Result authThird(HttpServletRequest request){
        User user = this.getAuthUser();
        return this.getSuccessResult(user);
    }

    /**
     * 用户管理
     * @return
     */
    @RequestMapping("/index.htm")
    public String index(){
        return "system/user/index";
    }

    /**
     * 用户详情页
     * @param id
     * @param request
     * @return
     */
    @RequestMapping(value ="/update.htm",method = RequestMethod.GET)
    public String update(String id, HttpServletRequest request){
        User user = this.userService.getById(Long.parseLong(id));
        List<Role> roleList = user.getRoleList();
        String password = user.getPasswd();
        if(StringUtils.isNotEmpty(password)){
            try {
                password = new String(EncryptUtil.decryptBASE64(password), "GB2312");
            } catch (Exception e) {
                logger.error(e.getMessage(),e);
                this.logger.error(e.getMessage());
                throw new BaseException(BaseConstants.ERR_COPYBEAN);
            }
        }
        user.setPasswd(password);
        if(user.getHireDate() != null){
            String hireDate = DateUtil.dateFormat(user.getHireDate());
            request.setAttribute("hireDate",hireDate);
        }
        if(user.getLeaveDate() != null){
            String leaveDate = DateUtil.dateFormat(user.getLeaveDate());
            request.setAttribute("leaveDate",leaveDate);
        }
        request.setAttribute("roleList",roleList);
        request.setAttribute("user",user);
        return "system/user/update";
    }

    /**
     * 查询用户信息
     * @param form
     * @return
     */
    @RequestMapping("/list")
    public Result list(UserListReq form){
        Page page = Page.getInstance(form);
        UserList userList = new UserList();
        try {
            BeanUtils.copyProperties(userList,form);
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
            logger.error(e.getMessage());
            throw new BaseException(BaseConstants.ERR_COPYBEAN);
        }
        page.setParams(userList);
        PageResultBO<User> resultBO = this.userService.listByPage(page);
        return getSuccessResult(resultBO);
    }

    /**
     * 新增用户
     * @param userReq
     * @return
     */
    @RequestMapping(value = "/add",method = RequestMethod.POST)
    public Result add(@Valid UserReq userReq,String roleIds,String orgCodes) throws BaseException {
        User authUser = getAuthUser();//获取当前操作人
        User user = new User();
        if(this.userService.getByCode(userReq.getCode())!=null){
            throw new BaseException(BaseConstants.ERR_DUPLICATE_DATA);
        }
        if (StringUtils.isEmpty(userReq.getPasswd())){
            return getFailResult(BaseConstants.ERR_UNKOWN,"密码不能为空！");
        }
        try {
            BeanUtils.copyProperties(user,userReq);
            if(StringUtils.isNotEmpty(userReq.getHireDate())){
                user.setHireDate(DateUtil.str2date(userReq.getHireDate()));
            }
            if(StringUtils.isNotEmpty(userReq.getLeaveDate())){
                user.setHireDate(DateUtil.str2date(userReq.getLeaveDate()));
            }
            String password = EncryptUtil.encryptBASE64(EncryptUtil.md5(userReq.getPasswd(), "UTF-8").getBytes());//MD5加密后存库
            user.setPasswd(password);
            user.setOrgCode(orgCodes);
            user.setSettlementType(userReq.getSettlementType());
            user.setState(StateEnum.Valid.getState());
            List<Long> roleIdLong = ParamUtils.convert2List(roleIds);
            if(authUser != null){
                user.setCreateUid(authUser.getId());
                user.setUpdateUid(authUser.getId());
                this.userService.add(user,roleIdLong);
            }
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
            this.logger.error(e.getMessage());
            return getFailResult(BaseConstants.ERR_UNKOWN,"新增失败");
        }
        return getSuccessResult("添加用户信息成功");
    }

    /**
     * 删除用户
     * @param id
     * @return
     */
    @RequestMapping("/delete")
    public Result delete(String id) throws BaseException{
        User authUser = getAuthUser();
        if((authUser.getId().toString()).equals(id)){
            return getFailResult(BaseConstants.ERR_CANNOT_DELETE_SELF,"用户不可删除自己");
        }
        if (StringUtils.isBlank(id)){
            return getFailResult(BaseConstants.ERR_INVALID_PARAMETER,"参数缺失");
        }
        try {
            this.userService.delete(id);
        } catch (BaseException e) {
            logger.error(e.getMessage(),e);
            logger.error(e.getMessage());
            return getFailResult(BaseConstants.ERR_UNKOWN,"删除失败");
        }
        return getSuccessResult("删除用户信息成功");
    }

    /**
     * 更新用户信息
     * @param userReq
     * @return
     */
    @RequestMapping(value = "/update",method = RequestMethod.POST)
    public Result update(@Valid UserReq userReq,String roleIds,String orgCodes) throws BaseException{
        User oldUser = userService.getById(Long.parseLong(userReq.getId()));
        if(oldUser == null){
            throw new BaseException(BaseConstants.ERR_NON_EXISTENT);
        }
        User user = new User();
        User authUser = getAuthUser();//获取当前操作人
        try {
            BeanUtils.copyProperties(user,userReq);
            if(StringUtils.isNotEmpty(userReq.getHireDate())){
                user.setHireDate(DateUtil.str2date(userReq.getHireDate()));
            }
            if(StringUtils.isNotEmpty(userReq.getLeaveDate())){
                user.setHireDate(DateUtil.str2date(userReq.getLeaveDate()));
            }
            if(StringUtils.isNotEmpty(userReq.getPasswd())){
                String password = EncryptUtil.encryptBASE64(EncryptUtil.md5(userReq.getPasswd(),"UTF-8").getBytes("UTF-8"));
                user.setPasswd(password);
            }
            user.setOrgCode(orgCodes);
            user.setUpdateUid(authUser.getId());
            user.setSettlementType(userReq.getSettlementType());
            List<Long> roleIdLong = ParamUtils.convert2List(roleIds);
            this.userService.update(user,authUser.getId(),roleIdLong, user.getCode());
        }catch (Exception e) {
            logger.error(e.getMessage(),e);
            this.logger.error(e.getMessage());
            return getFailResult(BaseConstants.ERR_UNKOWN,"更新失败");
        }

        List<Long> idList = new ArrayList<Long>();
        if (CollectionUtils.isNotEmpty(oldUser.getRoleList())){
            for (Role role:oldUser.getRoleList()){
                idList.add(role.getId());
            }
        }
        oldUser.setRoleList(null);
        oldUser.setRoleIdList(idList);
        String oldValue = null;
        try {
            oldValue = objectMapper.writeValueAsString(oldUser);
        }catch (JsonProcessingException e) {
            logger.error(e.getMessage(),e);
        }
        settingLogService.addLog(user, OpearteEnum.UPDATE, TargetEnum.USER_INFO,oldValue);
        return getSuccessResult("更新用户成功");
    }

    /**
     * 批量删除用户
     * @param ids
     * @return
     */
    @RequestMapping("/batchdel")
    public Result batchDel(String ids) throws BaseException{
        User authUser = getAuthUser();
        if (StringUtils.isBlank(ids)){
            return getFailResult(BaseConstants.ERR_INVALID_PARAMETER,"参数缺失");
        }
        List<String> list = Arrays.asList(ids.split(","));
        if(list.contains(authUser.getId().toString())){
            return getFailResult(BaseConstants.ERR_CANNOT_DELETE_SELF,"用户不可删除自己");
        }
        if(list.size() > 0){
            try {
                this.userService.batchDel(list);
            } catch (BaseException e) {
                logger.error(e.getMessage(),e);
                return getFailResult(BaseConstants.ERR_UNKOWN,"删除失败");
            }
        }
        return getSuccessResult("删除用户信息成功");
    }

    /**
     * 导出用户信息
     * @param form
     * @param response
     */
    @RequestMapping("/export")
    public void export(UserListReq form, HttpServletResponse response){
        Page page = Page.getInstance(form);
        UserList list = new UserList();
        try {
            BeanUtils.copyProperties(list,form);
            page.setParams(list);
            page.setLoadAll(true);
            PageResultBO<User> resultBO = userService.listByPage(page);
            response.setHeader("content-disposition", "attachment;filename=" + "User—"+ DateUtil.dateFormat(new Date(),"yyyy-MM-dd").toString() +".xlsx");
            List<User> userList = resultBO.getDataList();
            OutputStream out = response.getOutputStream();
            ExcelUtil<User> excelUtil = new ExcelUtil<User>(User.class);
            excelUtil.exportExcel(userList,"用户信息数据",out);
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
            logger.error(e.getMessage());
            throw new BaseException(BaseConstants.ERR_COPYBEAN);
        }
    }

    /**
     * 模板下载
     * */
    @RequestMapping("/exporttemplate")
    public void export(HttpServletResponse response){
        try {
            response.setHeader("content-disposition", "attachment;filename=" + "User—"+ DateUtil.dateFormat(new Date(),"yyyy-MM-dd").toString() +".xlsx");
            OutputStream out = response.getOutputStream();
            ExcelUtil<User> excelUtil = new ExcelUtil<User>(User.class);
            excelUtil.exportExcel( new ArrayList<User>(),"用户信息数据",out);
        }catch (Exception e){
            logger.error(e.getMessage(),e);
        }
    }

    /**
     * 用户导入
     * @param multipartFile
     * @return
     */
    @RequestMapping("/import")
    public Result importData(@RequestParam("file") CommonsMultipartFile[] multipartFile){
        InputStream in = null;
        User authUser = this.getAuthUser();
        List<User> errList = new ArrayList<User>();
        List<String> errMsg = new ArrayList<String>();
        List<User> users = new ArrayList<User>();
        String fileKey = "";
        int successNums = 0;
        int totalNums = 0;
        int threadNum = 20;
        Map retunMap = null;
        try {
            in = multipartFile[0].getInputStream();
            ExcelUtil<User> excelUtil = new ExcelUtil<User>(User.class);
            List<User> userAdd = excelUtil.importExcel("用户信息数据",in);
            List<String> codes = new ArrayList<String>();
            if(userAdd != null && userAdd.size() > 0){
                for(User user : userAdd){
                    String code = user.getCode();
                    codes.add(code);
                }
                users = this.userService.queryByCodes(codes);
                userAdd.removeAll(users);
                int totalSize = userAdd.size();
                //per
                ExecutorService executorService = Executors.newFixedThreadPool(threadNum);
                int num = totalSize / threadNum;
                if(0 == num){
                    threadNum = 1;
                }
                List<FutureTask<Map>> futureTasks = new ArrayList<FutureTask<Map>>();
                for(int i = 0; i < threadNum; i++) {
                    List<User> threadUsers = null;
                    if (i == threadNum - 1) {
                        threadUsers = userAdd.subList(i * num, totalSize);
                    } else {
                        threadUsers = userAdd.subList(i * num, num * (i + 1) > totalSize ? totalSize : num * (i + 1));
                    }
                    Thread.sleep(2000);
                    FutureTask<Map> task = new FutureTask<Map>(new ImportCallable(threadUsers, authUser.getId(), userService));
                    futureTasks.add(task);
                    executorService.submit(task);
                }
                for(FutureTask<Map> futureTask : futureTasks){
                    retunMap = futureTask.get();
                    errMsg.addAll((List<String>) retunMap.get("errMsg"));
                    errList.addAll((List<User>) retunMap.get("errList"));
                }
            }
            successNums = userAdd.size() - errList.size();
            totalNums = userAdd.size();
        }catch (Exception e){
            e.printStackTrace();
            logger.error(e.getMessage(),e);
        } finally {
            if(in != null){
                try {
                    in.close();
                } catch (IOException e) {
                    logger.error(e.getMessage(),e);
                }
            }
            if(errList != null && errList.size()>0){
                String path = getRealPath("");
                File file = null;
                try {
                    path += System.currentTimeMillis() + BaseConstants.DEFAULT_EXPORT_FILE_SUFFIX;
                    file = new File(path);
                    ExportBuilder builder = new ExportBuilder(UserImportTemplateBean.class,new UserParse());
                    ExportFactory factory = ExportFactory.getExportFactory(builder);
                    for(User user : users){
                        errMsg.add(BaseConstants.getErrorMessage(BaseConstants.ERR_DUPLICATE_DATA));
                        errList.add(user);
                    }
                    factory.setErrMsgList(errMsg).setDataList(errList).outPut(file);
                    fileKey = FileUtils.uploadFile("import/user/",file.getName(),file);
                }catch(Exception e){
                    logger.error(e.getMessage(),e);
                }finally {
                    if(file != null){
                        file.delete();
                    }
                }
            }
        }
        Map<String, String> returnMap = new HashMap<String, String>();
        returnMap.put("fileKey", fileKey);
        returnMap.put("successNums", String.valueOf(successNums));
        returnMap.put("totalNums", String.valueOf(totalNums));
        return getSuccessResult(returnMap);
    }

    /**
     * 下载出错的数据
     * */
    @RequestMapping("/down")
    public void importData(String fileKey,HttpServletResponse response){
        FileUtils.downFile(fileKey,response);
    }

    /**
     * 获取机构树
     * @return
     */
    @RequestMapping("/listorg")
    public Result listOrgnization(){
        List<Organization> organizations = organizationService.listAll();
        return getSuccessResult(organizations);
    }

    /**
     * 获取角色树
     * @return
     */
    @RequestMapping("/listrole")
    public Result listRole(){
        List<Role> roles = roleService.listRoles();
        return getSuccessResult(roles);
    }

    /**
     * 获取已选中的机构树
     * @return
     */
    @RequestMapping(value = "/checkedorg" ,method = RequestMethod.GET)
    public Result checkedOrg(String code){
        List<Organization> organizations;
        try {
            Organization org = organizationService.getByCode(code);
            organizations = this.organizationService.listAll();
            if( organizations != null && organizations.size() >0){
                for(Organization organization : organizations){
                    if(org != null && organization.getOrgCode().equals(org.getOrgCode())){
                        organization.setSelected(true);
                    }
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(),e);
            logger.error(e.getMessage());
            return getFailResult(BaseConstants.ERR_UNKOWN,"系统异常");
        }
        return getSuccessResult(organizations);
    }

    /**
     * 获取已选中的角色树
     * @return
     */
    @RequestMapping(value = "/checkedrole",method = RequestMethod.GET)
    public Result checkedRole(String userCode ){
        List<UserRoleRel> userRoleRels = userService.getRoleRelByUserCode(userCode);
        return getSuccessResult(userRoleRels);
    }
}
